package com.gnetek.tool.socket

import android.util.Log
import com.chhuang.tutool.socket.base.ISendable
import io.netty.bootstrap.Bootstrap
import io.netty.buffer.ByteBuf
import io.netty.buffer.Unpooled
import io.netty.channel.*
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.SocketChannel
import io.netty.channel.socket.nio.NioSocketChannel
import java.net.InetSocketAddress


class NettyClient(private val ip: String, private val port: Int,
                  private val success:(nettyClient: NettyClient)->Unit,
                  private val failed:()->Unit,
                  multipleFailed:()->Unit,
                  private val received:(content: ByteArray)->Unit) {

    companion object{
        private const val TAG = "NettyClient"

        private var nioEventLoopGroup: NioEventLoopGroup?=null
        private var socketChannel: SocketChannel? = null

    }

    private var isConnected = false

    private var failedIndex=0
    private val failedMax =20
    init {
        do{
            Log.e(TAG, "连接次数: $failedIndex")
            if(failedIndex<failedMax)connect()
            Thread.sleep(4500)
        }while (failedIndex<failedMax)

        if(failedIndex!=failedMax+failedMax){//成功是failedMax+failedMax
            multipleFailed()
        }
    }

    /**
     * 创建连接
     */
    private fun connect() {
        nioEventLoopGroup = NioEventLoopGroup()
        val bootstrap = Bootstrap()
        bootstrap.group(nioEventLoopGroup)
            .channel(NioSocketChannel::class.java)
            /**
             * Netty参数，用于Channel分配接受Buffer的分配器，
             * 默认值为AdaptiveRecvByteBufAllocator.DEFAULT，
             * 是一个自适应的接受缓冲区分配器，能根据接受到的数据自动调节大小。
             * 可选值为FixedRecvByteBufAllocator，固定大小的接受缓冲区分配器
             */
//            .option(ChannelOption.RCVBUF_ALLOCATOR, FixedRecvByteBufAllocator(65536))// 设置tcp缓冲区 有用
            .option(ChannelOption.RCVBUF_ALLOCATOR, AdaptiveRecvByteBufAllocator(3069, 4096, 65536))//设置tcp缓冲区 有用
            .option(ChannelOption.TCP_NODELAY, true)  //无阻塞
            .option(ChannelOption.SO_KEEPALIVE, true) //长连接
            .remoteAddress(InetSocketAddress(ip, port))
            .handler(object : ChannelInitializer<SocketChannel>(){
                override fun initChannel(ch: SocketChannel) {
//                    ch.pipeline().addLast(SmartIotEncoder())//发送编码方式
//                    ch.pipeline().addLast(SmartIotDecoder())//接收解码方式
                    ch.pipeline().addLast(object : SimpleChannelInboundHandler<ByteBuf>(){
                        override fun messageReceived(ctx: ChannelHandlerContext?, msg: ByteBuf?) {
                            Log.e(TAG, "messageReceived: 接收成功", )
                            msg?.let {
                                val len = it.readableBytes() //数据长度
                                val datas = ByteArray(len)
                                it.readBytes(datas) // 接收的数据
                                received(datas)
                            }
                        }
                    })
                }
            })
        try {
            val channelFuture = bootstrap.connect()
                .addListener(object : ChannelFutureListener {
                    override fun operationComplete(future: ChannelFuture) {
                        if (future.isSuccess) {
                            socketChannel = future.channel() as SocketChannel
                            isConnected = true
                            Log.e(TAG, "netty 连接成功 \n" +
                                    "(ip: ${socketChannel?.remoteAddress()?.address}, port: ${socketChannel?.remoteAddress()?.port})\n" +
                                    "(ip: ${socketChannel?.localAddress()?.address}, port: ${socketChannel?.localAddress()?.port})")
                            failedIndex=failedMax+failedMax
                            success(this@NettyClient)
                        } else {
                            Log.e(TAG, "netty 连接失败 (ip: ${ip}, port: ${port})")
                            future.channel().close()
                            nioEventLoopGroup?.shutdownGracefully()
                            failedIndex++
                            failed()
                        }
                    }
                }).sync()
                //阻塞，直到连接完成
//            channelFuture.channel().closeFuture().syncUninterruptibly()
            channelFuture.channel().closeFuture().sync()
        } catch (ex: Exception) {
            ex.printStackTrace()
            Log.e(TAG, "NettyServer: 启动失败")
            failed()
            //释放所有资源和创建的线程
            nioEventLoopGroup?.shutdownGracefully()
        }
    }

    /**
     * 获取本地ip与port信息
     */
    fun getLocalSocketAddress(): InetSocketAddress?{
        return if(isConnected())
            socketChannel?.localAddress()
        else
            null
    }

    fun isConnected(): Boolean {
        return isConnected
    }

    fun disConnected() {
        if(isConnected())
            socketChannel?.close()
        isConnected = false
    }

    fun destroy() {
        disConnected()
        nioEventLoopGroup?.shutdownGracefully()
        socketChannel = null
        isConnected = false
    }


    /**
     * 发送一个的消息，
     */
    fun sendMessage(datas: ByteArray){
        if (!isConnected()) {
            return
        }
        socketChannel?.run {
            writeAndFlush(Unpooled.copiedBuffer(datas)).addListener { future ->
                if (future.isSuccess) {
                    //消息发送成功
                    Log.e(TAG, "netty 消息发送成功")
                } else {
                    //消息发送失败
                    Log.e(TAG, "netty 消息发送失败")
                }
            }
        }
    }

    /**
     * 发送消息
     */
    fun sendMessage(sendable: ISendable) {
        sendMessage(sendable.parse())
    }

}